﻿/* 
 * Copyright (c) Intel Corporation
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * -- Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * -- Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * -- Neither the name of the Intel Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.IO;
using ExtensionLoader;
using ExtensionLoader.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using CableBeachMessages;
using OpenSimDbLinq;

namespace InventoryServer.Extensions.OpenSim
{
    public class OpenSimFilesystem : IExtension<InventoryServer>, IFilesystemProvider
    {
        const string EXTENSION_NAME = "OpenSimFilesystem"; // Used in metrics reporting

        InventoryServer server;
        OpenSimDatabase inventoryDatabase;

        public OpenSimFilesystem()
        {
        }

        public bool Start(InventoryServer server)
        {
            this.server = server;

            #region Config Loading

            try
            {
                IConfig extensionConfig = server.ConfigFile.Configs["OpenSimInventoryDatabase"];
                inventoryDatabase = OpenSimUtils.LoadDatabaseFromConfig(extensionConfig);

                try
                {
                    // DEBUG:
                    //inventoryDatabase.Log = Console.Out;

                    // Run a query to select the creation date of the first asset in the database to confirm
                    // that database access is working
                    var creationDateQuery = from item in inventoryDatabase.InventoryItems select item.CreationDate;
                    int result = creationDateQuery.FirstOrDefault();
                    if (result != 0)
                    {
                        DateTime creationDate = OpenMetaverse.Utils.UnixTimeToDateTime(result);
                        Logger.Info("[OpenSimFilesystem] Connected to inventory database that was initialized on " + creationDate);
                    }
                    else
                    {
                        Logger.Warn("[OpenSimFilesystem] Could not find any inventory items in the database. Either a connection problem or the database is empty");
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("[OpenSimFilesystem] Failed to establish a database connection: " + ex.Message);
                    return false;
                }
            }
            catch (Exception)
            {
                Logger.Error("[OpenSimFilesystem] Failed to load [OpenSimInventoryDatabase] section from " + InventoryServer.CONFIG_FILE);
                return false;
            }

            #endregion Config Loading

            return true;
        }

        public void Stop()
        {
        }

        #region IFilesystemProvider Methods

        public BackendResponse TryFetchItem(Uri owner, UUID agentID, UUID itemID, out InventoryItem item)
        {
            item = null;
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            try
            {
                lock (inventoryDatabase)
                {
                    string itemIDStr = itemID.ToString();
                    string ownerIDStr = ownerID.ToString();
                    var query = from row in inventoryDatabase.InventoryItems
                                where row.InventoryID == itemIDStr && row.AvatarID == ownerIDStr
                                select row;

                    InventoryItems dbItem = query.SingleOrDefault();

                    if (dbItem != null)
                    {
                        item = DatabaseToItem(dbItem);
                        response = BackendResponse.Success;
                    }
                    else
                    {
                        response = BackendResponse.NotFound;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error("[OpenSimFilesystem] Database fetch failed: " + ex.Message);
                response = BackendResponse.Failure;
            }

            server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, response, owner, itemID, false, DateTime.Now);
            return response;
        }

        public BackendResponse TryFetchFolder(Uri owner, UUID agentID, UUID folderID, out InventoryFolder folder)
        {
            folder = null;
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            try
            {
                lock (inventoryDatabase)
                {
                    string folderIDStr = folderID.ToString();
                    string ownerIDStr = ownerID.ToString();
                    var query = from row in inventoryDatabase.InventoryFolders
                                where row.FolderID == folderIDStr && row.AgentID == ownerIDStr
                                select row;

                    InventoryFolders dbFolder = query.SingleOrDefault();

                    if (dbFolder != null)
                    {
                        folder = DatabaseToFolder(dbFolder);
                        response = BackendResponse.Success;
                    }
                    else
                    {
                        response = BackendResponse.NotFound;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error("[OpenSimFilesystem] Database fetch failed: " + ex.Message);
                response = BackendResponse.Failure;
            }

            server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, response, owner, folderID, true, DateTime.Now);
            return response;
        }

        public BackendResponse TryFetchRootFolder(Uri owner, UUID agentID, out InventoryFolder rootFolder)
        {
            rootFolder = null;
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            try
            {
                lock (inventoryDatabase)
                {
                    string idZeroStr = UUID.Zero.ToString();
                    string ownerIDStr = ownerID.ToString();
                    var query = from row in inventoryDatabase.InventoryFolders
                                where row.ParentFolderID == idZeroStr && row.AgentID == ownerIDStr
                                select row;

                    InventoryFolders dbFolder = query.SingleOrDefault();

                    if (dbFolder != null)
                    {
                        rootFolder = DatabaseToFolder(dbFolder);
                        FetchSubItemsRecursively(ref rootFolder, ownerIDStr);
                        response = BackendResponse.Success;
                    }
                    else
                    {
                        response = BackendResponse.NotFound;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error("[OpenSimFilesystem] Database fetch failed: " + ex.Message);
                response = BackendResponse.Failure;
            }

            server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, response, owner, (rootFolder != null) ? rootFolder.ID : UUID.Zero, true, DateTime.Now);
            return response;
        }

        void FetchSubItemsRecursively(ref InventoryFolder folder, string ownerIDStr)
        {
            string folderIDStr = folder.ID.ToString();
            if (folder.Children == null)
                folder.Children = new Dictionary<UUID, InventoryBase>();

            var foldersQuery = from folders in inventoryDatabase.InventoryFolders
                               where folders.ParentFolderID == folderIDStr && folders.AgentID == ownerIDStr
                               select folders;

            foreach (InventoryFolders ifolder in foldersQuery)
            {
                UUID sFolderId = UUID.Parse(ifolder.FolderID);
                InventoryFolder sFolder = DatabaseToFolder(ifolder);
                FetchSubItemsRecursively(ref sFolder, ownerIDStr);
                folder.Children[sFolderId] = sFolder;
            }

            var itemsQuery = from items in inventoryDatabase.InventoryItems
                             where items.ParentFolderID == folderIDStr && items.AvatarID == ownerIDStr
                             select items;

            foreach (InventoryItems item in itemsQuery)
                folder.Children[UUID.Parse(item.InventoryID)] = DatabaseToItem(item);
        }

        public BackendResponse TryFetchFolderContents(Uri owner, UUID agentID, UUID folderID, out InventoryCollection contents)
        {
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            contents = new InventoryCollection();
            contents.UserID = ownerID;

            string ownerIDStr = ownerID.ToString();
            string folderIDStr = folderID.ToString();

            try
            {
                lock (inventoryDatabase)
                {
                    var foldersQuery = from folders in inventoryDatabase.InventoryFolders
                                       where folders.ParentFolderID == folderIDStr && folders.AgentID == ownerIDStr
                                       select folders;

                    contents.Folders = new Dictionary<UUID, InventoryFolder>(foldersQuery.Count());

                    foreach (InventoryFolders folder in foldersQuery)
                        contents.Folders[UUID.Parse(folder.FolderID)] = DatabaseToFolder(folder);

                    var itemsQuery = from items in inventoryDatabase.InventoryItems
                                     where items.ParentFolderID == folderIDStr && items.AvatarID == ownerIDStr
                                     select items;

                    contents.Items = new Dictionary<UUID, InventoryItem>(itemsQuery.Count());

                    foreach (InventoryItems item in itemsQuery)
                        contents.Items[UUID.Parse(item.InventoryID)] = DatabaseToItem(item);

                    response = BackendResponse.Success;
                }
            }
            catch (Exception ex)
            {
                Logger.Error("[OpenSimFilesystem] Database fetch failed: " + ex.Message);
                response = BackendResponse.Failure;
            }

            server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, response, owner, folderID, DateTime.Now);
            return response;
        }

        public BackendResponse TryFetchFolderList(Uri owner, UUID agentID, out List<InventoryFolder> folders)
        {
            folders = null;
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            string ownerIDStr = ownerID.ToString();

            try
            {
                lock (inventoryDatabase)
                {
                    var foldersQuery = from dbFolders in inventoryDatabase.InventoryFolders
                                       where dbFolders.AgentID == ownerIDStr
                                       select dbFolders;

                    folders = new List<InventoryFolder>(foldersQuery.Count());

                    foreach (InventoryFolders folder in foldersQuery)
                        folders.Add(DatabaseToFolder(folder));

                    response = BackendResponse.Success;
                }
            }
            catch (Exception ex)
            {
                Logger.Error("[OpenSimFilesystem] Database fetch failed: " + ex.Message);
                response = BackendResponse.Failure;
            }

            server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, response, owner, DateTime.Now);
            return response;
        }

        public BackendResponse TryFetchFilesystem(Uri owner, UUID agentID, out InventoryCollection inventory)
        {
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            inventory = new InventoryCollection();
            inventory.UserID = ownerID;
            inventory.DefaultFolders = new Dictionary<string,InventoryFolder>();

            string ownerIDStr = ownerID.ToString();

            try
            {
                lock (inventoryDatabase)
                {
                    var foldersQuery = from folders in inventoryDatabase.InventoryFolders
                                       where folders.AgentID == ownerIDStr
                                       select folders;

                    inventory.Folders = new Dictionary<UUID, InventoryFolder>(foldersQuery.Count());

                    foreach (InventoryFolders folder in foldersQuery)
                    {
                        InventoryFolder invFolder = DatabaseToFolder(folder);
                        inventory.Folders[UUID.Parse(folder.FolderID)] = invFolder;

                        // Check if this is the root folder
                        if (invFolder.ParentID == UUID.Zero)
                            inventory.RootFolderID = invFolder.ID;

                        // If this folder is a default folder for some content-type, add it to the list of default folders
                        short preferredType = invFolder.Type;
                        if (preferredType != -1)
                            inventory.DefaultFolders[CableBeachUtils.SLAssetTypeToContentType(preferredType)] = invFolder;
                    }

                    var itemsQuery = from items in inventoryDatabase.InventoryItems
                                     where items.AvatarID == ownerIDStr
                                     select items;

                    inventory.Items = new Dictionary<UUID, InventoryItem>(itemsQuery.Count());

                    foreach (InventoryItems item in itemsQuery)
                        inventory.Items[UUID.Parse(item.InventoryID)] = DatabaseToItem(item);

                    response = BackendResponse.Success;
                }
            }
            catch (Exception ex)
            {
                Logger.Error("[OpenSimFilesystem] Database fetch failed: " + ex.Message);
                response = BackendResponse.Failure;
            }

            server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, response, owner, DateTime.Now);
            return response;
        }

        public BackendResponse TryCreateItem(Uri owner, UUID agentID, InventoryItem item)
        {
            BackendResponse response;
            item.Creator = item.Owner = CableBeachUtils.MessageToUUID(owner, agentID);
            InventoryItems dbItem = ItemToDatabase(item);

            try
            {
                lock (inventoryDatabase)
                {
                    List<InventoryItems> insertList = new List<InventoryItems>(1);
                    insertList.Add(dbItem);
                    inventoryDatabase.InventoryItems.BulkInsert(insertList);
                    response = BackendResponse.Success;
                }
            }
            catch (Exception)
            {
                // TODO: Parse the exception to figure out if it was a primary key error or database connection error
                try
                {
                    lock (inventoryDatabase)
                    {
                        string itemIDStr = item.ID.ToString();
                        InventoryItems existingRow = (from row in inventoryDatabase.InventoryItems where row.InventoryID == itemIDStr select row).First();
                        UpdateDBItem(ref existingRow, dbItem);
                        inventoryDatabase.SubmitChanges();
                        response = BackendResponse.Success;
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("[OpenSimFilesystem] Database update failed: " + ex.Message);
                    response = BackendResponse.Failure;
                }
            }

            server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, response, owner, false, DateTime.Now);
            return response;
        }

        public BackendResponse TryCreateFolder(Uri owner, UUID agentID, InventoryFolder folder)
        {
            BackendResponse response;
            folder.Owner = CableBeachUtils.MessageToUUID(owner, agentID);
            InventoryFolders dbFolder = FolderToDatabase(folder);

            try
            {
                lock (inventoryDatabase)
                {
                    List<InventoryFolders> insertList = new List<InventoryFolders>(1);
                    insertList.Add(dbFolder);
                    inventoryDatabase.InventoryFolders.BulkInsert(insertList);
                    response = BackendResponse.Success;
                }
            }
            catch (Exception)
            {
                // TODO: Parse the exception to figure out if it was a primary key error or database connection error
                try
                {
                    lock (inventoryDatabase)
                    {
                        string folderIDStr = folder.ID.ToString();
                        InventoryFolders existingRow = (from row in inventoryDatabase.InventoryFolders where row.FolderID == folderIDStr select row).First();
                        UpdateDBFolder(ref existingRow, dbFolder);
                        inventoryDatabase.SubmitChanges();
                        response = BackendResponse.Success;
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("[OpenSimFilesystem] Database update failed: " + ex.Message);
                    response = BackendResponse.Failure;
                }
            }

            server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, response, owner, true, DateTime.Now);
            return response;
        }

        public BackendResponse TryCreateFilesystem(Uri owner, UUID agentID, InventoryFolder rootFolder)
        {
            BackendResponse response = TryCreateFolder(owner, agentID, rootFolder);

            server.MetricsProvider.LogInventoryCreateInventory(EXTENSION_NAME, response, DateTime.Now);
            return response;
        }

        public BackendResponse TryDeleteItem(Uri owner, UUID agentID, UUID itemID)
        {
            BackendResponse response;
            InventoryItems deleteItem = new InventoryItems();
            deleteItem.InventoryID = itemID.ToString();
            deleteItem.AvatarID = CableBeachUtils.MessageToUUID(owner, agentID).ToString();

            lock (inventoryDatabase)
            {
                try
                {
                    inventoryDatabase.InventoryItems.DeleteOnSubmit(deleteItem);
                    inventoryDatabase.SubmitChanges();
                    response = BackendResponse.Success;
                }
                catch (Exception ex)
                {
                    Logger.Error("[OpenSimFilesystem] Database delete failed: " + ex.Message);
                    inventoryDatabase.InventoryItems.CancelDeleteOnSubmit(deleteItem);
                    response = BackendResponse.Failure;
                }
            }

            server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, response, owner, itemID, false, DateTime.Now);
            return response;
        }

        public BackendResponse TryDeleteFolder(Uri owner, UUID agentID, UUID folderID)
        {
            BackendResponse response;

            // Purge the folder first
            TryPurgeFolder(owner, agentID, folderID);

            // Create an inventory object to do the delete on
            InventoryFolders deleteFolder = new InventoryFolders();
            deleteFolder.FolderID = folderID.ToString();
            deleteFolder.AgentID = CableBeachUtils.MessageToUUID(owner, agentID).ToString();

            lock (inventoryDatabase)
            {
                try
                {
                    inventoryDatabase.InventoryFolders.DeleteOnSubmit(deleteFolder);
                    inventoryDatabase.SubmitChanges();
                    response = BackendResponse.Success;
                }
                catch (Exception ex)
                {
                    Logger.Error("[OpenSimFilesystem] Database delete failed: " + ex.Message);
                    inventoryDatabase.InventoryFolders.CancelDeleteOnSubmit(deleteFolder);
                    response = BackendResponse.Failure;
                }
            }

            server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, response, owner, folderID, true, DateTime.Now);
            return response;
        }

        public BackendResponse TryPurgeFolder(Uri owner, UUID agentID, UUID folderID)
        {
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            string folderIDStr = folderID.ToString();
            string ownerIDStr = ownerID.ToString();
            List<UUID> subfolders = new List<UUID>();

            // Fetch all of the subfolders, since they will need to be purged
            lock (inventoryDatabase)
            {
                try
                {
                    var foldersQuery = from folders in inventoryDatabase.InventoryFolders
                                       where folders.ParentFolderID == folderIDStr && folders.AgentID == ownerIDStr
                                       select folders.FolderID;

                    foreach (string childFolderIDStr in foldersQuery)
                        subfolders.Add(UUID.Parse(childFolderIDStr));
                }
                catch (Exception ex)
                {
                    Logger.Error("[OpenSimFilesystem] Failed to fetch subfolders to purge: " + ex.Message);
                    response = BackendResponse.Failure;
                }
            }

            // Recursively purge all of the subfolders
            for (int i = 0; i < subfolders.Count; i++)
                TryPurgeFolder(owner, agentID, subfolders[i]);

            // Purge the folders and items in this folder
            lock (inventoryDatabase)
            {
                try
                {
                    inventoryDatabase.InventoryItems.DeleteAllOnSubmit(inventoryDatabase.InventoryItems.Where(
                        item => item.ParentFolderID == folderIDStr && item.AvatarID == ownerIDStr));
                    inventoryDatabase.InventoryFolders.DeleteAllOnSubmit(inventoryDatabase.InventoryFolders.Where(
                        folder => folder.ParentFolderID == folderIDStr && folder.AgentID == ownerIDStr));
                    inventoryDatabase.SubmitChanges();
                    response = BackendResponse.Success;
                }
                catch (Exception ex)
                {
                    Logger.Error("[OpenSimFilesystem] Database purge failed: " + ex.Message);
                    response = BackendResponse.Failure;
                }
            }

            server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, response, owner, folderID, DateTime.Now);
            return response;
        }

        public BackendResponse TryFetchActiveGestures(Uri owner, UUID agentID, out List<InventoryItem> gestures)
        {
            gestures = null;
            BackendResponse response;
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);

            string ownerIDStr = ownerID.ToString();

            try
            {
                lock (inventoryDatabase)
                {
                    var itemsQuery = from items in inventoryDatabase.InventoryItems
                                     where items.Flags != 0 && items.AvatarID == ownerIDStr
                                     select items;

                    gestures = new List<InventoryItem>(itemsQuery.Count());

                    foreach (InventoryItems item in itemsQuery)
                        gestures.Add(DatabaseToItem(item));

                    response = BackendResponse.Success;
                }
            }
            catch (Exception ex)
            {
                Logger.Error("[OpenSimFilesystem] Database fetch failed: " + ex.Message);
                response = BackendResponse.Failure;
            }

            server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, response, owner, DateTime.Now);
            return response;
        }

        public UUID GetDefaultAsset(Uri owner, UUID agentID, string contentType)
        {
            Logger.Warn("[OpenSimFilesystem] Returning default assetID of UUID.Zero for " + contentType);
            return UUID.Zero;
        }

        public UUID GetDefaultParent(Uri owner, UUID agentID, string contentType)
        {
            UUID ownerID = CableBeachUtils.MessageToUUID(owner, agentID);
            string ownerIDStr = ownerID.ToString();

            try
            {
                lock (inventoryDatabase)
                {
                    // Look for a folder for the preferred asset type set to the requested content type
                    short assetType = (short)CableBeachUtils.ContentTypeToSLAssetType(contentType);

                    var parentQuery = from dbFolder in inventoryDatabase.InventoryFolders
                                      where dbFolder.Type == assetType && dbFolder.AgentID == ownerIDStr
                                      select dbFolder.FolderID;

                    var parentFolderID = parentQuery.First();

                    if (parentFolderID != null)
                        return UUID.Parse(parentFolderID);
                }
            }
            catch (Exception e) { }

            try
            {
                lock (inventoryDatabase)
                {
                    // Try to grab the root folder
                    string idZeroStr = UUID.Zero.ToString();
                    var parentQuery = from dbFolder in inventoryDatabase.InventoryFolders
                                      where dbFolder.ParentFolderID == idZeroStr && dbFolder.AgentID == ownerIDStr
                                      select new { dbFolder.FolderID };

                    var parentFolder = parentQuery.First();

                    if (parentFolder != null)
                        return UUID.Parse(parentFolder.FolderID);
                }
            }
            catch (Exception) { }

            Logger.Warn("[OpenSimFilesystem] Couldn't find any default folder for owner: " + owner + ", content type: " + contentType);
            return UUID.Zero;
        }

        public UUID IdentityToUUID(Uri owner)
        {
            UUID id;

            if (owner.Host.Equals(server.HttpUri.Host, StringComparison.InvariantCultureIgnoreCase))
            {
                // This is a local user identity, try to parse the first and last name out
                string[] firstLast = owner.Segments[owner.Segments.Length - 1].Split('_', '.');

                if (firstLast.Length == 2)
                {
                    string firstName = firstLast[0];
                    string lastName = firstLast[1];

                    lock (inventoryDatabase)
                    {
                        var userQuery = from user in inventoryDatabase.Users
                                        where user.UserName == firstName && user.LastName == lastName
                                        select user.UUID;
                        string uuidStr = userQuery.FirstOrDefault();

                        if (!String.IsNullOrEmpty(uuidStr) && UUID.TryParse(uuidStr, out id))
                            return id;
                    }
                }
            }

            return CableBeachUtils.IdentityToUUID(owner);
        }

        #endregion IFilesystemProvider Methods

        #region Helper Methods

        InventoryItem DatabaseToItem(InventoryItems dbItem)
        {
            InventoryItem item = new InventoryItem();
            item.AssetID = UUID.Parse(dbItem.AssetID);
            item.AssetType = dbItem.AssetType;
            item.BasePermissions = dbItem.InventoryBasePermissions;
            item.CreationDate = dbItem.CreationDate;
            item.Creator = UUID.Parse(dbItem.CreatorID);
            item.CurrentPermissions = dbItem.InventoryCurrentPermissions;
            item.Description = dbItem.InventoryDescription;
            item.EveryOnePermissions = dbItem.InventoryEveryOnePermissions;
            item.Flags = dbItem.Flags;
            item.GroupID = UUID.Parse(dbItem.GroupID);
            item.GroupOwned = dbItem.GroupOwned != 0;
            item.GroupPermissions = dbItem.InventoryGroupPermissions;
            item.ID = UUID.Parse(dbItem.InventoryID);
            item.InvType = dbItem.InvType;
            item.Name = dbItem.InventoryName;
            item.NextPermissions = dbItem.InventoryNextPermissions;
            item.Owner = UUID.Parse(dbItem.AvatarID);
            item.ParentID = UUID.Parse(dbItem.ParentFolderID);
            item.SalePrice = dbItem.SalePrice;
            item.SaleType = (byte)dbItem.SaleType;

            return item;
        }

        InventoryFolder DatabaseToFolder(InventoryFolders dbFolder)
        {
            InventoryFolder folder = new InventoryFolder();
            folder.ID = UUID.Parse(dbFolder.FolderID);
            folder.Name = dbFolder.FolderName;
            folder.Owner = UUID.Parse(dbFolder.AgentID);
            folder.ParentID = UUID.Parse(dbFolder.ParentFolderID);
            folder.Type = dbFolder.Type;
            folder.Version = (ushort)dbFolder.Version;

            return folder;
        }

        InventoryItems ItemToDatabase(InventoryItem item)
        {
            InventoryItems dbItem = new InventoryItems();
            dbItem.AssetID = item.AssetID.ToString();
            dbItem.AssetType = item.AssetType;
            dbItem.AvatarID = item.Owner.ToString();
            dbItem.CreationDate = item.CreationDate;
            dbItem.CreatorID = item.Creator.ToString();
            dbItem.Flags = item.Flags;
            dbItem.GroupID = item.GroupID.ToString();
            dbItem.GroupOwned = (sbyte)(item.GroupOwned ? 1 : 0);
            dbItem.InventoryBasePermissions = item.BasePermissions;
            dbItem.InventoryCurrentPermissions = item.CurrentPermissions;
            dbItem.InventoryDescription = item.Description;
            dbItem.InventoryEveryOnePermissions = item.EveryOnePermissions;
            dbItem.InventoryGroupPermissions = item.GroupPermissions;
            dbItem.InventoryID = item.ID.ToString();
            dbItem.InventoryName = item.Name;
            dbItem.InventoryNextPermissions = item.NextPermissions;
            dbItem.InvType = item.InvType;
            dbItem.ParentFolderID = item.ParentID.ToString();
            dbItem.SalePrice = item.SalePrice;
            dbItem.SaleType = (sbyte)item.SaleType;

            return dbItem;
        }

        InventoryFolders FolderToDatabase(InventoryFolder folder)
        {
            InventoryFolders dbFolder = new InventoryFolders();
            dbFolder.AgentID = folder.Owner.ToString();
            dbFolder.FolderID = folder.ID.ToString();
            dbFolder.FolderName = folder.Name;
            dbFolder.ParentFolderID = folder.ParentID.ToString();
            dbFolder.Type = folder.Type;
            dbFolder.Version = folder.Version;

            return dbFolder;
        }

        void UpdateDBItem(ref InventoryItems existingItem, InventoryItems item)
        {
            existingItem.AssetID = item.AssetID;
            existingItem.AssetType = item.AssetType;
            existingItem.AvatarID = item.AvatarID;
            existingItem.CreationDate = item.CreationDate;
            existingItem.CreatorID = item.CreatorID;
            existingItem.Flags = item.Flags;
            existingItem.GroupID = item.GroupID;
            existingItem.GroupOwned = item.GroupOwned;
            existingItem.InventoryBasePermissions = item.InventoryBasePermissions;
            existingItem.InventoryCurrentPermissions = item.InventoryCurrentPermissions;
            existingItem.InventoryDescription = item.InventoryDescription;
            existingItem.InventoryEveryOnePermissions = item.InventoryEveryOnePermissions;
            existingItem.InventoryGroupPermissions = item.InventoryGroupPermissions;
            //existingItem.InventoryID = item.InventoryID;
            existingItem.InventoryName = item.InventoryName;
            existingItem.InventoryNextPermissions = item.InventoryNextPermissions;
            existingItem.InvType = item.InvType;
            existingItem.ParentFolderID = item.ParentFolderID;
            existingItem.SalePrice = item.SalePrice;
            existingItem.SaleType = item.SaleType;
        }

        void UpdateDBFolder(ref InventoryFolders existingFolder, InventoryFolders folder)
        {
            existingFolder.AgentID = folder.AgentID;
            //existingFolder.FolderID = folder.FolderID;
            existingFolder.FolderName = folder.FolderName;
            existingFolder.ParentFolderID = folder.ParentFolderID;
            existingFolder.Type = folder.Type;
            existingFolder.Version = folder.Version;
        }

        #endregion Helper Methods
    }
}
